Understanding String Immutability in Java
Course: Core Java Training
Topic: Understanding String Immutability
Course Link: Core Java Training Course
Demo Link: Register for a Free Demo
JustAcademy Homepage: Visit JustAcademy
1. Introduction to String Immutability
In Java, a String is an object that represents a sequence of characters. String immutability means that once a String object has been created, its character content cannot be changed. Operations such as concatenation, replacing characters, converting text to uppercase, or extracting a substring produce a result without modifying the original String object.
The Java String class is declared as final, and its API specifies that String values cannot be changed after creation. This makes Strings suitable for sharing between different parts of an application.
Example
public class StringImmutability {
public static void main(String[] args) {
String message = "Hello";
message.concat(" Java");
System.out.println(message);
}
}
Output:
Hello
The concat() method returns a String containing the combined text, but the original String referenced by message remains unchanged. The returned value was not assigned to a variable.
2. Learning Objectives
- Understand the meaning of immutability in Java.
- Learn why String objects cannot be modified after creation.
- Understand the difference between a String object and a variable reference.
- Explore how concatenation and other String methods behave.
- Understand the relationship between String immutability and the String pool.
- Compare String with mutable classes such as StringBuilder and StringBuffer.
- Identify the advantages and limitations of immutable Strings.
- Apply String immutability concepts in practical Java programs.
3. What Does Immutable Mean?
An immutable object is an object whose state cannot be changed after it has been created. In Java, the value represented by a String remains the same throughout the object's lifetime.
For example, the String "Java" cannot be modified to become "Python" by changing its existing characters. Instead, Java operations can produce another String containing the new text.
Immutable Object Example
String language = "Java";
language = "Python";
System.out.println(language);
Output:
Python
This example does not mean the original String object changed. The variable language is reassigned to refer to a String containing "Python". The original String value "Java" remains unchanged.
Key Terms
| Term |
Meaning |
| Immutable |
An object's state cannot be changed after creation. |
| Mutable |
An object's state can be modified after creation. |
| String |
A Java class representing an immutable sequence of characters. |
| Reference variable |
A variable that refers to an object. |
| Reassignment |
Changing which object a variable refers to. |
| String pool |
A JVM-managed pool used to reuse certain String instances. |
4. Why Are Strings Immutable in Java?
String immutability is an important design feature of Java. It provides several benefits related to security, reliability, sharing, and predictable behavior.
4.1 Security
Strings are commonly used to represent file paths, URLs, configuration values, class names, and other security-sensitive information. If a String could change unexpectedly after validation, a program might use a different value from the one it checked.
Immutability helps ensure that a String value remains stable while it is being validated or passed to another method. It does not, by itself, make every application secure; appropriate validation and access controls are still necessary.
4.2 Thread Safety
Because a String's content cannot change, multiple threads can safely read the same String object without needing synchronization to protect the String's contents. However, a shared variable that refers to a String can still be reassigned, and the surrounding application may require synchronization.
4.3 String Pool Support
Java can reuse String objects with the same content through the String pool. Since the content of a pooled String cannot be modified, one part of a program cannot change the shared String value and unexpectedly affect other references to that object.
4.4 Reliable Hash Codes
Strings are frequently used as keys in hash-based collections such as HashMap and HashSet. Their immutable content allows the result of hashCode() to remain consistent for the same String value, supporting reliable collection lookups.
4.5 Predictable Program Behavior
When a method receives a String, it can rely on that object's content remaining unchanged. This makes String values easier to share, cache, compare, and pass between methods.
5. How String Immutability Works
String methods that appear to modify text actually return a String representing the result. The original String object remains unchanged.
Example: Concatenation
public class StringConcatExample {
public static void main(String[] args) {
String first = "Core";
String second = first.concat(" Java");
System.out.println("First: " + first);
System.out.println("Second: " + second);
}
}
Output:
First: Core
Second: Core Java
The variable first still refers to the String containing "Core". The variable second refers to the resulting String containing "Core Java".
Example: Assigning the Result Back
String text = "Hello";
text = text.concat(" World");
System.out.println(text);
Output:
Hello World
The result is assigned to text. The variable now refers to the resulting String, but the original String was not modified.
6. String Methods and Immutability
Many commonly used String methods return new String values or return an existing value when no change is needed. They do not mutate the original String object.
| Method |
Purpose |
Example |
Original String Changed? |
concat() |
Combines text |
s.concat(" Java") |
No |
toUpperCase() |
Converts text to uppercase |
s.toUpperCase() |
No |
toLowerCase() |
Converts text to lowercase |
s.toLowerCase() |
No |
replace() |
Replaces matching characters or sequences |
s.replace('a', 'o') |
No |
substring() |
Extracts part of a String |
s.substring(0, 3) |
No |
trim() |
Removes certain leading and trailing characters at or below U+0020 |
s.trim() |
No |
strip() |
Removes leading and trailing Unicode whitespace |
s.strip() |
No |
Example: Uppercase Conversion
public class UppercaseExample {
public static void main(String[] args) {
String course = "core java";
String upper = course.toUpperCase();
System.out.println(course);
System.out.println(upper);
}
}
Output:
core java
CORE JAVA
Example: Replacing Text
public class ReplaceExample {
public static void main(String[] args) {
String original = "I like tea";
String updated = original.replace("tea", "coffee");
System.out.println(original);
System.out.println(updated);
}
}
Output:
I like tea
I like coffee
The variable original continues to refer to the String "I like tea". The replacement result is stored separately in updated.
7. String Immutability and Reference Variables
It is important to distinguish between changing an object's contents and reassigning a reference variable. A String reference can be reassigned even though the String object itself is immutable.
public class ReferenceExample {
public static void main(String[] args) {
String value = "Java";
System.out.println(value);
value = value.toUpperCase();
System.out.println(value);
}
}
Output:
Java
JAVA
The first statement prints the original value. The uppercase operation returns a String containing "JAVA", and the assignment makes value refer to that result.
Important Difference
- Changing an object: Modifies the state of the same object.
- Reassigning a reference: Makes a variable refer to another object or value.
- String behavior: Its content is immutable, but its reference variable can be reassigned unless the variable itself is declared
final.
8. String Immutability and the String Pool
The String pool is a JVM-managed mechanism for reusing String instances. String literals are interned, allowing identical literal values to refer to the same pooled instance in appropriate circumstances.
Example
public class StringPoolExample {
public static void main(String[] args) {
String first = "Java";
String second = "Java";
System.out.println(first == second);
System.out.println(first.equals(second));
}
}
Output:
true
true
Both variables refer to the same pooled String instance in this example. The == operator compares references, whereas equals() compares String content.
Comparing a Literal and a New String Object
public class StringReferenceComparison {
public static void main(String[] args) {
String first = "Java";
String second = new String("Java");
System.out.println(first == second);
System.out.println(first.equals(second));
}
}
Output:
false
true
The explicit constructor creates a distinct String object in this example. Both objects contain the same text, so equals() returns true, but their references differ. In ordinary code, creating a String with new String("Java") is generally unnecessary.
9. String Immutability and the final Keyword
The final keyword can prevent a variable from being reassigned after it has been initialized. It is separate from String immutability, which applies to the String object's content.
public class FinalStringExample {
public static void main(String[] args) {
final String language = "Java";
System.out.println(language);
// This reassignment would cause a compile-time error:
// language = "Python";
}
}
The reference variable language cannot be reassigned because it is declared final. A normal String reference without final can be reassigned, but no String object's content can be modified through ordinary String operations.
10. String vs StringBuilder vs StringBuffer
Java provides different classes for handling text. String is immutable, while StringBuilder and StringBuffer provide mutable character sequences.
| Feature |
String |
StringBuilder |
StringBuffer |
| Mutability |
Immutable |
Mutable |
Mutable |
| Can append text in place? |
No; returns a resulting String |
Yes |
Yes |
| Common use |
Fixed text and values shared across code |
Repeated text construction in typical single-threaded code |
Text modification when synchronized methods are useful |
| Synchronization |
Not needed to protect String contents |
Methods are not synchronized by default |
Methods are synchronized |
| Typical performance use |
Good for fixed text and simple operations |
Often suitable for repeated appends |
May have synchronization overhead |
Example: StringBuilder
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder("Core");
builder.append(" Java");
builder.append(" Training");
System.out.println(builder);
}
}
Output:
Core Java Training
The StringBuilder object's contents are modified by the append operations. This differs from String concatenation, which produces a String result.
Example: StringBuffer
public class StringBufferExample {
public static void main(String[] args) {
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" World");
System.out.println(buffer);
}
}
Output:
Hello World
StringBuffer provides synchronized methods for its mutable operations. Synchronization on these methods does not automatically make every larger operation involving the buffer atomic.
11. Performance Considerations
String immutability offers simplicity and safety, but repeated String concatenation can create additional intermediate String results. When building large amounts of text through repeated operations, a mutable class such as StringBuilder is often a more suitable choice.
Less Suitable for Repeated Concatenation
public class StringLoopExample {
public static void main(String[] args) {
String result = "";
for (int i = 1; i <= 5; i++) {
result = result + i + " ";
}
System.out.println(result);
}
}
Output:
1 2 3 4 5
Using StringBuilder
public class StringBuilderLoopExample {
public static void main(String[] args) {
StringBuilder result = new StringBuilder();
for (int i = 1; i <= 5; i++) {
result.append(i).append(" ");
}
System.out.println(result);
}
}
Output:
1 2 3 4 5
Both programs produce the same visible text. For repeated concatenation, StringBuilder can reduce intermediate String creation. The exact performance difference depends on the operation, compiler, and Java runtime; simple concatenation expressions may be optimized by the compiler.
12. Advantages of String Immutability
- Security: Validated String values cannot be modified through ordinary String methods.
- Thread safety: Multiple threads can read the same String content without synchronization to protect that content.
- String pooling: Identical literal values can be shared safely.
- Stable hash codes: String content remains consistent for hash-based collection usage.
- Predictability: Methods receiving a String can rely on its content remaining unchanged.
- Ease of sharing: Immutable values can be passed between methods without defensive copying to protect their contents.
- Simpler reasoning: Code does not need to account for another method modifying the content of an existing String.
13. Limitations of String Immutability
- Repeated concatenation in loops may create unnecessary intermediate String results.
- Changing a String requires producing or selecting another String value and assigning it if the result should be retained.
- String objects may remain in memory until they are no longer reachable and reclaimed by the garbage collector.
- Immutability does not guarantee that sensitive text is erased from memory immediately.
- String immutability does not make a mutable reference variable or an entire application thread-safe.
14. Common Mistakes and Troubleshooting
| Mistake |
Why It Happens |
Correct Approach |
Ignoring the result of concat() |
The original String remains unchanged. |
Assign the result to a variable if you need to keep it. |
Assuming toUpperCase() modifies the original |
String methods return a result instead of mutating the original. |
Store the returned value or use it directly. |
Using == to compare String content |
== compares references. |
Use equals() for exact content comparison. |
| Thinking a reassigned variable changed an old String |
Variable reassignment is confused with object mutation. |
Remember that the variable now refers to a String with the new value. |
| Using String for heavy repeated appends |
Repeated operations may create intermediate results. |
Consider StringBuilder. |
| Assuming immutable means secret data is erased |
Immutability prevents content changes but does not guarantee memory erasure. |
Use appropriate security practices for sensitive information. |
| Assuming all String variables are constant |
The String object is immutable, but a normal reference can be reassigned. |
Use final when a reference should not be reassigned. |
15. Best Practices for Working with Strings
- Use String for text values that do not need repeated in-place modification.
- Use
equals() when comparing String contents.
- Assign the result of methods such as
concat(), replace(), and toUpperCase() when you need to retain the transformed value.
- Use
StringBuilder for repeated string construction, especially in loops.
- Use
StringBuffer when its synchronized methods fit the application's requirements.
- Remember that
final String prevents reassignment of that variable but does not create a different kind of String object.
- Avoid creating unnecessary String objects with the
new String(...) constructor.
- Handle sensitive text carefully; immutability alone does not remove data from memory.
- Use clear variable names to distinguish original values from transformed results.
16. Practical Example: Formatting a Course Name
This example demonstrates how multiple String operations return results without modifying the original String.
public class CourseNameFormatter {
public static void main(String[] args) {
String courseName = " core java training ";
String cleaned = courseName.trim();
String formatted = cleaned.toUpperCase();
String completeName = formatted.concat(" COURSE");
System.out.println("Original: [" + courseName + "]");
System.out.println("Cleaned: [" + cleaned + "]");
System.out.println("Formatted: " + formatted);
System.out.println("Complete: " + completeName);
}
}
Output:
Original: [ core java training ]
Cleaned: [core java training]
Formatted: CORE JAVA TRAINING
Complete: CORE JAVA TRAINING COURSE
The original String retains its leading and trailing spaces. Each subsequent variable stores a result returned by a String operation.
17. Practice Exercises
- Basic Immutability: Create a String containing
"Java", call concat(" Programming"), and print the original and returned values.
- Uppercase Conversion: Convert a lowercase String to uppercase and demonstrate that the original value remains unchanged.
- Replace Text: Replace a word in a sentence and print both the original and replacement result.
- Reference Reassignment: Assign a new String value to a variable and explain why this does not modify the original String object.
- String Pool: Compare two identical String literals using both
== and equals().
- Constructor Comparison: Compare a String literal with a String created using
new String().
- StringBuilder: Append five words using StringBuilder and display the combined result.
- Performance Practice: Build a sequence of numbers using String concatenation and StringBuilder, then compare the code and output.
- Formatting: Remove surrounding whitespace, convert text to uppercase, and append a suffix without changing the original value.
18. Mini Project: Immutable Text Formatter
Objective: Build a simple Java program that receives a course name and creates formatted versions of it while preserving the original String.
Requirements
- Create an original String containing a course name with extra spaces.
- Remove leading and trailing whitespace from a resulting String.
- Convert the cleaned result to uppercase.
- Append a label to the formatted String.
- Display the original and each transformed value.
- Use StringBuilder to combine multiple labels efficiently.
Sample Implementation
public class ImmutableTextFormatter {
public static void main(String[] args) {
String original = " core java ";
String cleaned = original.trim();
String uppercase = cleaned.toUpperCase();
String labeled = uppercase.concat(" - BEGINNER COURSE");
StringBuilder report = new StringBuilder();
report.append("Original: ").append(original).append("\n");
report.append("Cleaned: ").append(cleaned).append("\n");
report.append("Uppercase: ").append(uppercase).append("\n");
report.append("Labeled: ").append(labeled);
System.out.println(report);
}
}
Expected Output:
Original: core java
Cleaned: core java
Uppercase: CORE JAVA
Labeled: CORE JAVA - BEGINNER COURSE
This project demonstrates String immutability, reassignment through separate variables, String transformations, and mutable text construction with StringBuilder.
19. Interview Questions and Answers
Q1. What is String immutability in Java?
String immutability means that the content of a String object cannot be changed after the object has been created.
Q2. Why is String immutable in Java?
Immutability supports security, safe sharing, predictable behavior, String pooling, and reliable use of Strings as hash-based collection keys.
Q3. Does the concat() method modify the original String?
No. It returns a String representing the concatenated result. The original String remains unchanged.
Q4. Can a String variable change its value?
A normal String reference variable can be reassigned to refer to another String value. This does not modify the content of the original String object.
Q5. What is the difference between String and StringBuilder?
String is immutable, whereas StringBuilder is mutable and allows its character sequence to be modified through methods such as append().
Q6. What is the String pool?
The String pool is a JVM-managed mechanism that enables reuse of interned String instances, including String literals.
Q7. Why should equals() usually be used instead of == for Strings?
equals() compares String content, while == checks whether two references point to the same object.
Q8. How does immutability help with thread safety?
Multiple threads can read the same String object without synchronization to protect its content because that content cannot be changed through normal String operations.
Q9. Does declaring a String reference as final make the String immutable?
String is already immutable. The final keyword prevents that reference variable from being reassigned after initialization.
Q10. When should StringBuilder be used?
StringBuilder is useful when text needs to be constructed through repeated operations, especially in loops.
Q11. Can an immutable String be changed through toUpperCase()?
No. The method returns an uppercase String result while leaving the original String unchanged.
Q12. Does String immutability guarantee that sensitive data is erased from memory?
No. Immutability prevents the String object's content from being modified through normal String methods, but it does not guarantee immediate memory erasure.
20. Quick Revision Checklist
- String objects are immutable in Java.
- String methods return results instead of modifying the original content.
- Reference variables can be reassigned unless declared
final.
- Use
equals() for String content comparison.
- Use
== to compare references when reference identity is what you need.
- The String pool can reuse interned String instances.
- Immutable Strings are useful for safe sharing and predictable behavior.
- StringBuilder and StringBuffer are mutable alternatives.
- StringBuilder is often appropriate for repeated text construction.
- Immutability does not guarantee that sensitive data is erased from memory.
21. Conclusion
String immutability is a fundamental concept in Core Java. Once a String object is created, its content cannot be changed through ordinary String methods. Operations such as concatenation, replacement, and case conversion return results while preserving the original String value. Understanding the difference between an object and its reference helps prevent common programming mistakes.
String immutability also supports safe sharing, predictable behavior, and String pooling. When a program needs frequent text modifications, StringBuilder or StringBuffer may be more appropriate. Practice these concepts through small programs to build a strong foundation in Java string handling.
22. Further Learning Resources
Continue your learning with the JustAcademy Core Java Training Course, register for a demo session, or visit the JustAcademy homepage.